#include "msg_queue.h"
#include "msg.h"
extern "C"{
#include "libavutil/avstring.h"
#include "libavutil/eval.h"
#include "libavutil/mathematics.h"
#include "libavutil/pixdesc.h"
#include "libavutil/imgutils.h"
#include "libavutil/dict.h"
#include "libavutil/parseutils.h"
#include "libavutil/samplefmt.h"
#include "libavutil/avassert.h"
#include "libavutil/time.h"
#include "libavutil/display.h"
#include "libavformat/avformat.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
#include "libavutil/opt.h"
#include "libavcodec/avfft.h"
#include "libswresample/swresample.h"

//#ifdef __cplusplus
}

void msg_free_res(AVMessage *msg)
{
    if(!msg || !msg->obj){
        return ;
    }
    msg->free_l(msg->obj);
    msg->obj = NULL;
}

int msg_queue_put_private(MessageQueue *q, AVMessage *msg)
{
    AVMessage *msg1;
    if(q->abort_request){
        return -1;
    }
    if(q->recycle_msg){
        msg1 = q->recycle_msg;
        q->recycle_msg=msg1->next;
        msg1->next= NULL;
        q->recycle_count++;
    }else{
        msg1 = (AVMessage*)av_malloc(sizeof(AVMessage));
        q->alloc_count++;
    }
    //浅拷贝
    *msg1 = *msg;
    //插入
    if(!q->first_msg){
        q->first_msg = msg1;
        q->last_msg=msg1;
    }else {
        q->last_msg->next= msg1;
        q->last_msg=msg1;
    }

    q->nb_messages++;
    SDL_CondSignal(q->cond);
    return 0;
}

int msg_queue_put(MessageQueue *q, AVMessage *msg)
{
    int ret;
    SDL_LockMutex(q->mutex);
    ret= msg_queue_put_private(q,msg);
    SDL_UnlockMutex(q->mutex);
    return ret;
}
/* return < 0 if aborted, 0 if no msg and > 0 if msg. */
int msg_queue_get(MessageQueue *q, AVMessage *msg, int block)
{
    AVMessage* msg1;
    int ret ;

    SDL_LockMutex(q->mutex);

    for(;;){
        if(q->abort_request){
           ret = -1 ;
           break;
        }
        msg1 = q->first_msg;
        if(msg1){
            ret = 1;
            q->first_msg = msg1->next;
            if(!q->first_msg){
                q->last_msg=q->first_msg;
            }
            q->nb_messages--;
            *msg = *msg1;
            msg1->obj = NULL;
            msg1->next = q->recycle_msg;
            q->recycle_msg=msg1;
            ret = 1;
            break;
        }else if(block){
            SDL_CondWait(q->cond,q->mutex);
        }else{
            ret = 0;
            break;
        }


    }
    SDL_UnlockMutex(q->mutex);
    return ret;
}



void msg_init_msg(AVMessage *msg)
{
    memset(msg,0,sizeof(AVMessage));
}


void msg_queue_put_simple1(MessageQueue *q, int what)
{
    AVMessage msg1;
    msg_init_msg(&msg1);
    msg1.what=what;
    msg_queue_put(q,&msg1);


}

void msg_queue_put_simple2(MessageQueue *q, int what, int arg1)
{
    AVMessage msg1;
    msg_init_msg(&msg1);
    msg1.what=what;
    msg1.arg1 = arg1;
    msg_queue_put(q,&msg1);
}

void msg_queue_put_simple3(MessageQueue *q, int what, int arg1, int arg2)
{
    AVMessage msg1;
    msg_init_msg(&msg1);
    msg1.what=what;
    msg1.arg1 = arg1;
    msg1.arg2 = arg2;
    msg_queue_put(q,&msg1);
}

void msg_queue_put_simple4(MessageQueue *q, int what, int arg1, int arg2, void *obj, int obj_len)
{
    AVMessage msg1;
    msg_init_msg(&msg1);
    msg1.what=what;
    msg1.arg1 = arg1;
    msg1.arg2 = arg2;
    msg1.obj = av_malloc(obj_len);
    memcpy(msg1.obj,obj,obj_len);
    msg1.free_l = msg_obj_free_l;
    msg_queue_put(q,&msg1);
}

void msg_obj_free_l(void *obj)
{
    av_free(obj);
}

void msg_queue_init(MessageQueue *q)
{
    memset(q,0,sizeof(MessageQueue));
    q->mutex = SDL_CreateMutex();
    q->cond  =SDL_CreateCond();
    q->abort_request = 1;
}

void msg_queue_flush(MessageQueue *q)
{
    AVMessage *msg1=NULL,*msg2=NULL;
    SDL_LockMutex(q->mutex);
    msg2=q->first_msg;
    for(;;){
        msg1=msg2;
        msg2= msg1->next;
        msg1->next=q->recycle_msg;
        q->recycle_msg=msg1;
        if(!msg2){
            break;
        }
    }
    SDL_UnlockMutex(q->mutex);
    q->first_msg = NULL ;
    q->last_msg = NULL ;
    q->nb_messages = 0;
}

void msg_queue_destroy(MessageQueue *q)
{
    msg_queue_flush(q);
    SDL_LockMutex(q->mutex);
    for(;;){
        AVMessage* msg1 = q->recycle_msg;
        if(!msg1) break;
        q->recycle_msg = q->recycle_msg->next;
        msg_free_res(msg1);
        av_free(msg1);
    }
    SDL_UnlockMutex(q->mutex);
    SDL_DestroyMutex(q->mutex);
    SDL_DestroyCond(q->cond);
}
void msg_queue_abort(MessageQueue *q){
    SDL_LockMutex(q->mutex);
    q->abort_request=1;
    SDL_CondSignal(q->cond);
    SDL_UnlockMutex(q->mutex);

}
// 启⽤消息队列
void msg_queue_start(MessageQueue *q){
    SDL_LockMutex(q->mutex);
    q->abort_request=0;
    AVMessage msg;
    msg_init_msg(&msg);
    msg.what = MSG_FULSH;
    //SDL_CondSignal(q->cond);
    msg_queue_put_private(q,&msg);
    SDL_UnlockMutex(q->mutex);
}

void msg_queue_remove(MessageQueue *q, int what)
{

    AVMessage **p_msg, *msg, *last_msg;
        SDL_LockMutex(q->mutex);

        last_msg = q->first_msg;

        if (!q->abort_request && q->first_msg) {
            p_msg = &q->first_msg;
            while (*p_msg) {
                msg = *p_msg;
                if (msg->what == what) {        // 同类型的消息全部删除
                    *p_msg = msg->next;
                    msg_free_res(msg);
                    msg->next = q->recycle_msg;     // 消息体回收
                    q->recycle_msg = msg;
                    q->nb_messages--;
                } else {
                    last_msg = msg;
                    p_msg = &msg->next;
                }
            }

            if (q->first_msg) {
                q->last_msg = last_msg;
            } else {
                q->last_msg = NULL;
            }
        }

        SDL_UnlockMutex(q->mutex);
}
